package org.xbl.xchain.sdk;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.googlecode.jsonrpc4j.JsonRpcHttpClient;
import lombok.NoArgsConstructor;
import org.bouncycastle.util.encoders.Hex;
import org.xbl.xchain.sdk.amino.Codec;
import org.xbl.xchain.sdk.exception.WrongQueryParamException;
import org.xbl.xchain.sdk.module.auth.querier.AuthAccount;
import org.xbl.xchain.sdk.querier.Querier;
import org.xbl.xchain.sdk.types.TxResponse;
import org.xbl.xchain.sdk.types.Msg;
import org.xbl.xchain.sdk.tx.StdTx;
import org.xbl.xchain.sdk.types.*;
import org.xbl.xchain.sdk.utils.JsonRpcClientHelper;

import java.net.URL;
import java.util.*;

@NoArgsConstructor
public class Submitter {
    private SysConfig sysConfig;

    private TxConfig txConfig;


    public Submitter(SysConfig sysConfig) {
        this.sysConfig = sysConfig;
        this.txConfig = new TxConfig();
    }

    public Submitter(SysConfig sysConfig, TxConfig txConfig) {
        this.sysConfig = sysConfig;
        this.txConfig = txConfig;
    }

    public TxResponse submit(byte[] txBytes, TxMode txMode) {
        TxResponse txResponse = null;
        try {
            JSONObject params = new JSONObject();
            params.put("tx", txBytes);
            JsonRpcHttpClient client = JsonRpcClientHelper.getClient(sysConfig.getRpcUrl());
            Object result = client.invoke(txMode.getRpcMethod(), params, Object.class);
            if (txMode.getMode().equals(TxMode.BLOCK.getMode())) {
                txResponse = new TxResponse();
                txResponse.initForModeBlockResult(JSON.toJSONString(result));
            } else {
                txResponse = JSON.parseObject(JSON.toJSONString(result), TxResponse.class);
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return txResponse;
    }

    public TxResponse submit(Msg msg, Account sender, TxConfig txConfig) throws Exception {
        if (Version.SEQUENCE.equals(this.sysConfig.getVersion())) {
            sender.setAuthAccount(this.queryAuthAccount(sender.getAddress()));
        }
        byte[] txBytes = TxBuilder.buildTx(sysConfig, msg, sender, txConfig);
        TxResponse submit = this.submit(txBytes, txConfig.getTxMode());
        return submit;
    }

    public TxResponse submit(List<? extends Msg> msgs, Account sender, TxConfig txConfig) throws Exception {
        if (Version.SEQUENCE.equals(this.sysConfig.getVersion())) {
            sender.setAuthAccount(this.queryAuthAccount(sender.getAddress()));
        }
        byte[] txBytes = TxBuilder.buildTx(sysConfig, msgs, Arrays.asList(sender), txConfig);
        TxResponse submit = this.submit(txBytes, txConfig.getTxMode());
        return submit;
    }

//    public TxResponse submit(List<? extends Msg> msgs, List<Account> operatorKeys) throws Exception {
//        return this.submit(msgs, operatorKeys, this.txConfig);
//    }

    public AuthAccount queryAuthAccount(String address) throws WrongQueryParamException {
        XchainClient xchainClient = new XchainClient(sysConfig.getRpcUrl());
        return xchainClient.queryAuthAccount(address);
    }

    public Submitter withTxConfig(TxConfig txConfig) {
        this.txConfig = txConfig;
        return this;
    }
}
